let constants = require('./constants')
let utils = require('./utils')
let Session = require('./session')
let loginLib = require('./login')

let noop = function noop() {}

let buildAuthHeader = function buildAuthHeader(session) {
    let header = {}

    if (session) {
        header[constants.WX_HEADER_SKEY] = session
    }

    return header
}

/***
 * @class
 * 表示请求过程中发生的异常
 */
let RequestError = (function () {
    function RequestError(type, message) {
        Error.call(this, message)
        this.type = type
        this.message = message
    }

    RequestError.prototype = new Error()
    RequestError.prototype.constructor = RequestError

    return RequestError
})()

function request(options) {
    if (typeof options !== 'object') {
        let message = '请求传参应为 object 类型，但实际传了 ' + (typeof options) + ' 类型'
        throw new RequestError(constants.ERR_INVALID_PARAMS, message)
    }

    let requireLogin = options.login
    let success = options.success || noop
    let fail = options.fail || noop
    let complete = options.complete || noop
    let originHeader = options.header || {}

    // 成功回调
    let callSuccess = function () {
        success.apply(null, arguments)
        complete.apply(null, arguments)
    }

    // 失败回调
    let callFail = function (error) {
        fail.call(null, error)
        complete.call(null, error)
    }

    // 是否已经进行过重试
    let hasRetried = false

    if (requireLogin) {
        doRequestWithLogin()
    } else {
        doRequest()
    }

    // 登录后再请求
    function doRequestWithLogin() {
        loginLib.loginWithCode({ success: doRequest, fail: callFail })
    }

    // 实际进行请求的方法
    function doRequest() {
        let authHeader = {}

        let session = Session.get()

        if (session) {
            authHeader = buildAuthHeader(session.skey)
        }

        wx.request(utils.extend({}, options, {
            header: utils.extend({}, originHeader, authHeader),

            success: function (response) {
                let data = response.data

                let error; let
                    message
                if ((data && data.code === '-1') || response.statusCode === 401) {
                    Session.clear()
                    // 如果是登录态无效，并且还没重试过，会尝试登录后刷新凭据重新请求
                    if (!hasRetried) {
                        hasRetried = true
                        doRequestWithLogin()
                        return
                    }

                    message = '登录态已过期'
                    error = new RequestError(data.error, message)

                    callFail(error)
                    return
                } else {
                    callSuccess.apply(null, arguments)
                }
            },

            fail: callFail,
            complete: noop,
        }))
    }

}

module.exports = {
    RequestError: RequestError,
    request: request,
}